import json
import os
from PyQt6.QtGui import QCursor, QPainter, QTextOption, QTextLayout, QColor, QPixmap
from matplotlib.figure import Figure
from sklearn.metrics import mean_squared_error

from again.Data_Management_page.DataManagerwidget_new import Ui_DataManagerwidget
import picture.resources_rc
import sys
from PyQt6 import QtWidgets, QtCore, uic, QtGui
from PyQt6.QtWidgets import QTableWidget, QVBoxLayout, QLabel, QStackedWidget, QWidget, QApplication, QFileDialog, \
    QMessageBox, QTableWidgetItem, QInputDialog, QPushButton, QScrollArea, QHBoxLayout, QMenu, QDialog, QSizePolicy, \
    QRadioButton, QLineEdit, QListWidgetItem, QFrame, QButtonGroup, QCheckBox, QHeaderView, QComboBox
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
from PyQt6.QtCore import Qt, QTimer, QCoreApplication, QEvent, pyqtSignal, QObject, QDateTime
import pandas as pd
from matplotlib.animation import FuncAnimation
from TypeSetting_main import TypeSettingWindow
import concurrent.futures
from joblib import Parallel, delayed
from again.Train.GradientBoostingRegressor import GradientBoostingModel
from again.Train.SVM import SupportVectorMachineModel
from again.Train.Ridge import RidgeRegressionModel
class TrainModelDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("训练模型")

        # 设置对话框布局
        layout = QVBoxLayout()

        # 名称
        self.name_label = QLabel("名称:")
        self.name_input = QLineEdit()
        layout.addWidget(self.name_label)
        layout.addWidget(self.name_input)

        # 类型
        self.type_label = QLabel("类型:")
        self.type_input = QLineEdit()
        layout.addWidget(self.type_label)
        layout.addWidget(self.type_input)

        # 子模型说明
        self.submodel_label = QLabel("子模型说明:")
        self.submodel_input = QLineEdit()
        layout.addWidget(self.submodel_label)
        layout.addWidget(self.submodel_input)

        # 确定和取消按钮
        button_layout = QHBoxLayout()
        self.ok_button = QPushButton("确定")
        self.cancel_button = QPushButton("取消")

        button_layout.addWidget(self.ok_button)
        button_layout.addWidget(self.cancel_button)
        layout.addLayout(button_layout)

        # 设置主布局
        self.setLayout(layout)

        # 连接按钮信号
        self.ok_button.clicked.connect(self.accept)
        self.cancel_button.clicked.connect(self.reject)

    def get_data(self):
        return {
            "name": self.name_input.text(),
            "type": self.type_input.text(),
            "submodel": self.submodel_input.text(),
        }

# 项目数据文件
MODEL_FILE = 'model.json'

def save_projects(projects):
    with open(MODEL_FILE, 'w', encoding='utf-8') as f:
        json.dump(projects, f, indent=4, ensure_ascii=False)

def load_projects():
    if os.path.exists(MODEL_FILE):
        with open(MODEL_FILE, 'r', encoding='utf-8') as f:
            try:
                return json.load(f)
            except json.JSONDecodeError:
                return []
    return []



# 模型界面第一页模型管理表格类
class ModelTableProjectManager:
    def __init__(self, table_widget):
        self.table_widget = table_widget
        self.selected_row = None
        self.filtered_projects = []  # 存储从JSON中获取的数据
        self.radio_button_group = QButtonGroup()
        self.radio_button_group.setExclusive(True)  # 设置为互斥
    def setup_modelTable(self):
        # 禁用列宽调整
        header = self.table_widget.horizontalHeader()
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Fixed)

        # 设置列宽
        self.set_column_widths([50, 50, 100, 100, 100, 200, 100, 200, 150, 100])

    def set_column_widths(self, widths):
        for i, width in enumerate(widths):
            self.table_widget.setColumnWidth(i, width)

    def load_model_table(self, filtered_projects):
        self.table_widget.setRowCount(0)
        self.filtered_projects = filtered_projects

        for idx, project in enumerate(self.filtered_projects):
            self.add_modelData_to_table(idx, project)
            self.add_radio_button_to_table(idx)  # 为每一行添加一个单选按钮

        # 设置默认选中项
        for idx, project in enumerate(self.filtered_projects):
            if project["state"] == "已创建":
                widget = self.table_widget.cellWidget(idx, 0)  # 获取嵌套的 QWidget
                if widget:
                    # 从 QWidget 中查找 QRadioButton
                    radio_button = widget.findChild(QRadioButton)
                    if radio_button:
                        radio_button.setChecked(True)  # 设置为选中状态

    def add_radio_button_to_table(self, row):
        # 创建 QRadioButton
        radio_button = QRadioButton()
        # 将 radio_button 添加到 QButtonGroup 中进行管理
        self.radio_button_group.addButton(radio_button, row)
        # 创建一个 QWidget 并设置布局
        widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(radio_button)
        # 设置布局的上下左右边距为 0
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(Qt.AlignmentFlag.AlignCenter)  # 设置布局中心对齐
        widget.setLayout(layout)

        # 将 QWidget 设置到表格单元格中
        self.table_widget.setCellWidget(row, 0, widget)
    # def add_radio_button_to_table(self, row):
    #     radio_button = QRadioButton()
    #     radio_button.toggled.connect(self.on_radio_button_toggled)
    #     self.table_widget.setCellWidget(row, 0, radio_button)

    def add_modelData_to_table(self, idx, project):
        row_position = self.table_widget.rowCount()
        self.table_widget.insertRow(row_position)

        # 添加数据到各列
        self.add_item(row_position, 1, str(idx + 1))  # 序号
        self.add_item(row_position, 2, project["ID"])
        self.add_item(row_position, 3, project["name"])
        self.add_item(row_position, 4, project["type"])
        self.add_item(row_position, 5, project["created_time"])
        self.add_item(row_position, 6, project["state"])
        self.add_item(row_position, 7, project["submodel"])
        self.add_item(row_position, 8, project["train_set"])
        self.add_item(row_position, 9, project["Validation_set"])

    def add_item(self, row, col, text):
        item = QtWidgets.QTableWidgetItem(text)
        item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)  # 设置内容居中对齐
        self.table_widget.setItem(row, col, item)

    def on_radio_button_toggled(self):
        # 每次有新的按钮被选中时取消其他按钮的选中状态
        for row in range(self.table_widget.rowCount()):
            radio_button = self.table_widget.cellWidget(row, 0)
            if radio_button and radio_button.isChecked():
                self.selected_row = row
                break


# 模型界面第三页参数设置子模型选择类
class SubModelTableManager:
    def __init__(self, table_widget, main_class_ref):
        self.table_widget = table_widget
        self.main_class_ref = main_class_ref  # 保留对 MainClass 的引用
        self.selected_row = None
        # 创建 QButtonGroup 来管理单选按钮的互斥性
        self.radio_button_group = QButtonGroup()
        self.radio_button_group.setExclusive(True)  # 设置为互斥
        self.hyperparameter_settings = {}  # 用于存储每行的超参数设置

    def setup_modelTable(self, width_list):
        # 禁用列宽调整
        header = self.table_widget.horizontalHeader()
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Fixed)
        # 设置列宽
        self.set_column_widths(width_list)

    def set_column_widths(self, widths):
        for i, width in enumerate(widths):
            self.table_widget.setColumnWidth(i, width)

    def load_model_table(self, subModel):
        self.table_widget.setRowCount(0)  # 清空表格

        for idx, project in enumerate(subModel):
            self.add_modelData_to_table(idx, project)
            self.add_radio_button_to_table(idx)  # 为每一行添加一个单选按钮

        # 设置表格高度
        self.adjust_table_height()

    def add_radio_button_to_table(self, row):
        check_box = QCheckBox()  # 创建复选框
        check_box.setChecked(False)  # 默认不选中

        # 创建一个 QWidget 并设置布局
        widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(check_box)

        # 设置布局的上下左右边距为 0
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(Qt.AlignmentFlag.AlignCenter)  # 设置布局中心对齐
        widget.setLayout(layout)

        # 将 QWidget 设置到表格单元格中
        self.table_widget.setCellWidget(row, 0, widget)

    def add_modelData_to_table(self, idx, project):
        row_position = self.table_widget.rowCount()
        self.table_widget.insertRow(row_position)

        # 添加数据到各列
        self.add_item(row_position, 1, project["name"])
        # self.add_item(row_position, 2, str(idx + 1))

        # 添加超参数设置按钮
        button = QPushButton("超参数设置")

        # 传递当前行号和数据给按钮点击事件
        button.clicked.connect(lambda: self.open_hyperparameter_dialog(idx, project))
        self.table_widget.setCellWidget(row_position, 2, button)

    def open_hyperparameter_dialog(self, idx, project):
        try:
            dialog = HyperparameterDialog()
            if dialog.exec() == QDialog.DialogCode.Accepted:
                param1 = dialog.param1_input.text()
                param2 = dialog.param2_input.text()
                param3 = dialog.param3_input.text()
                param4 = dialog.param4_input.text()
                param5 = dialog.param5_input.text()
                param6 = dialog.param6_input.text()
                param7 = dialog.param7_input.text()

                # 将参数存储到字典中，使用 idx 作为键
                self.hyperparameter_settings[idx] = {
                    'param1': param1,
                    'param2': param2,
                    'param3': param3,
                    'param4': param4,
                    'param5': param5,
                    'param6': param6,
                    'param7': param7,
                }

                # 将超参数数据存储到 主类 的变量中
                self.main_class_ref.hyperparameter_data["Hyperparameter"+str(idx)] = self.hyperparameter_settings[idx]
                print(f"为第 {idx + 1} 行的项目 '{project['name']}' 设置了超参数: {param1}, {param2}, {param3}, {param4}, {param5}, {param6}, {param7}")

                # 主类中的hyperparameter_data
                print("当前的 hyperparameter_data:", self.main_class_ref.hyperparameter_data)
        except Exception as e:
            print(f"处理对话框时出现异常: {e}")

    def get_hyperparameter_settings(self):
        # 获取指定行的超参数设置
        return self.hyperparameter_settings
    def add_item(self, row, col, text):
        item = QtWidgets.QTableWidgetItem(text)
        item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)  # 设置内容居中对齐
        self.table_widget.setItem(row, col, item)

    def on_radio_button_toggled(self):
        # 每次有新的按钮被选中时取消其他按钮的选中状态
        for row in range(self.table_widget.rowCount()):
            radio_button = self.table_widget.cellWidget(row, 0)
            if radio_button and radio_button.isChecked():
                self.selected_row = row
                break

    def adjust_table_height(self):
        # 获取表头高度
        header_height = self.table_widget.horizontalHeader().height()

        # 计算所有行的总高度
        total_height = header_height
        for row in range(self.table_widget.rowCount()):
            total_height += self.table_widget.rowHeight(row)

        # 设置表格高度
        self.table_widget.setFixedHeight(total_height)

# 模型界面第四页数据集结论表格类
class ModelTableResultManager:
    def __init__(self, main_window):
        self.main_window = main_window
        self.table_widget = self.main_window.findChild(QTableWidget, "tableWidgetConclusion")
        # 持久化存储模型结果
        self.model_results_list = []

    def update_table(self, model_results):
        # 将新的模型结果添加到持久化列表
        self.model_results_list.append(model_results)

        # 设置表头
        headers = [
            "序号", "任务类型", "寻优方式", "模型类型",
            "训练时间", "训练集R²", "测试集R²",
            "训练集MSE", "测试集MSE",
            "交叉验证得分", "交叉验证平均得分",
            # "梯度提升特征重要性"
        ]
        self.table_widget.setColumnCount(len(headers))
        self.table_widget.setHorizontalHeaderLabels(headers)

        # 获取当前表格的行数（即已有的行数，用于递增序号）
        current_row_count = self.table_widget.rowCount()

        # 插入新数据
        row_position = current_row_count  # 新行的位置是当前行数
        self.table_widget.insertRow(row_position)

        # 设置序号（从1开始）
        self.table_widget.setItem(row_position, 0, QTableWidgetItem(f"{row_position + 1}"))

        # 填充其他数据，保留五位小数
        self.table_widget.setItem(row_position, 1, QTableWidgetItem(f"{model_results['task_type']}"))
        self.table_widget.setItem(row_position, 2, QTableWidgetItem(f"{model_results['model_type']}"))
        self.table_widget.setItem(row_position, 3, QTableWidgetItem(f"{model_results['model_name']}"))

        # 创建右对齐的 QTableWidgetItem 并设置对齐方式
        def right_aligned_item(text):
            item = QTableWidgetItem(text)
            item.setTextAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)  # 右对齐并垂直居中
            return item

        # 填充右对齐的列
        self.table_widget.setItem(row_position, 4, right_aligned_item(f"{model_results['train_time']:.3f}"))
        self.table_widget.setItem(row_position, 5, right_aligned_item(f"{model_results['r2_train']:.3f}"))
        self.table_widget.setItem(row_position, 6, right_aligned_item(f"{model_results['r2_test']:.3f}"))
        self.table_widget.setItem(row_position, 7, right_aligned_item(f"{model_results['mse_train']:.3f}"))
        self.table_widget.setItem(row_position, 8, right_aligned_item(f"{model_results['mse_test']:.3f}"))
        self.table_widget.setItem(row_position, 9, right_aligned_item(str(np.round(model_results['cv_scores'], 4))))
        self.table_widget.setItem(row_position, 10, right_aligned_item(f"{model_results['cv_mean_score']:.3f}"))
        # 调整每一列的宽度，使其根据内容自动调整
        self.table_widget.resizeColumnsToContents()
        # 对于特征重要性，格式化为字典字符串
        # feature_importances = ', '.join(
        #     [f"{feature}: {importance:.2%}" for feature, importance in model_results['feature_importances'].items()]
        # )
        # self.table_widget.setItem(row_position, 10, QTableWidgetItem(feature_importances))

        # 动态调整表格和父控件的高度
        self.adjust_table_height()

    def adjust_table_height(self):
        # 获取表头高度
        header_height = self.table_widget.horizontalHeader().height()

        # 计算所有行的总高度
        total_height = header_height
        for row in range(self.table_widget.rowCount()):
            total_height += self.table_widget.rowHeight(row)

        # 设置表格高度
        self.table_widget.setFixedHeight(total_height)

# 模型界面第四页loss曲线填充类
# class ImageWidget(QWidget):
#     def __init__(self, parent=None):
#         super().__init__(parent)
#         self.current_image_path = None
#
#     def paintEvent(self, event):
#         if self.current_image_path and os.path.exists(self.current_image_path):
#             pixmap = QPixmap(self.current_image_path)
#             if not pixmap.isNull():
#                 painter = QPainter(self)
#                 painter.drawPixmap(self.rect(), pixmap.scaled(self.size(), Qt.AspectRatioMode.KeepAspectRatio))
#             else:
#                 print(f"Failed to load image: {self.current_image_path}")
#         else:
#             print("Image path does not exist or is invalid.")
class ImageWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.current_image_path = None

    def paintEvent(self, event):
        if self.current_image_path:
            painter = QPainter(self)
            pixmap = QPixmap(self.current_image_path)
            if not pixmap.isNull():
                painter.drawPixmap(self.rect(), pixmap)
            else:
                print(f"加载图片失败: {self.current_image_path}")
        else:
            print("没有图片路径")

class ImageComboBoxController:
    def __init__(self, widget_loss_main):
        # 找到 QComboBox 实例
        self.combo_box = widget_loss_main.findChild(QComboBox, "comboBoxModelTypePic")
        self.combo_box.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)  # 自适应宽度
        # 设置大小策略，允许 QComboBox 在内容改变时调整大小
        # self.combo_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)

        self.image_widget = ImageWidget(widget_loss_main)
        self.image_widget.setFixedSize(950, 570)
        self.image_widget.setStyleSheet("background-color: white;")  # 设置背景颜色

        # 找到 widgetLossPic，并将 image_widget 设置为其子控件
        widget_loss_main.findChild(QWidget, "widgetLossPic").layout().addWidget(self.image_widget)

        # 字典存储下拉框选项和对应图片路径
        self.image_paths = {}
        self.current_image_path = None


    def connect_signals(self):
        """连接信号到槽函数"""
        if self.combo_box:
            connected = self.combo_box.currentIndexChanged.connect(self.on_combo_box_changed)
            print("信号已连接到 on_combo_box_changed" if connected else "信号未连接")
        else:
            print("未找到 comboBox")

    def on_combo_box_changed(self, index):
        """当下拉框改变时，调用该函数更新图片"""
        print(f"ComboBox index changed: {index}")
        current_text = self.combo_box.currentText()
        print(f"当前选项文本: {current_text}")
        self.update_image()

    def add_item(self, combo_box_text, image_path):
        """添加下拉框项和对应的图片路径"""
        print(f"添加下拉框项: {combo_box_text} -> {image_path}")
        self.combo_box.addItem(combo_box_text)
        self.image_paths[combo_box_text] = image_path
        print(f"当前 image_paths 字典: {self.image_paths}")


    def update_image(self):
        """根据当前下拉框的选项更新图片"""
        current_text = self.combo_box.currentText()
        print(f"当前下拉框选项: {current_text}")
        if current_text in self.image_paths:
            new_image_path = self.image_paths[current_text]
            if new_image_path != self.image_widget.current_image_path:
                print(f"新图片路径: {new_image_path}")
                self.image_widget.current_image_path = new_image_path
                self.image_widget.update()  # 请求重绘
            else:
                print("当前显示的图片已是最新图片")
        else:
            print(f"未找到下拉框选项: {current_text} 对应的路径")

    def initialize_combobox(self):
        """初始化下拉框，选择第二个项并更新图像"""
        if self.combo_box.count() > 0:
            self.combo_box.setCurrentIndex(0)  # 设置默认选择为第二项
            self.update_image()  # 更新图像
# 超参数设置
class HyperparameterDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("超参数设置")
        self.setFixedSize(300, 200)

        layout = QVBoxLayout()

        self.param1_input = QLineEdit(self)
        self.param1_input.setPlaceholderText("参数1")
        layout.addWidget(self.param1_input)

        self.param2_input = QLineEdit(self)
        self.param2_input.setPlaceholderText("参数2")
        layout.addWidget(self.param2_input)

        self.param3_input = QLineEdit(self)
        self.param3_input.setPlaceholderText("参数3")
        layout.addWidget(self.param3_input)

        self.param4_input = QLineEdit(self)
        self.param4_input.setPlaceholderText("参数4")
        layout.addWidget(self.param4_input)

        self.param5_input = QLineEdit(self)
        self.param5_input.setPlaceholderText("参数5")
        layout.addWidget(self.param5_input)

        self.param6_input = QLineEdit(self)
        self.param6_input.setPlaceholderText("参数6")
        layout.addWidget(self.param6_input)

        self.param7_input = QLineEdit(self)
        self.param7_input.setPlaceholderText("参数7")
        layout.addWidget(self.param7_input)

        button_layout = QHBoxLayout()
        self.confirm_button = QPushButton("确定", self)
        self.cancel_button = QPushButton("取消", self)

        button_layout.addWidget(self.confirm_button)
        button_layout.addWidget(self.cancel_button)
        layout.addLayout(button_layout)

        self.setLayout(layout)

        # 连接按钮的信号槽
        self.confirm_button.clicked.connect(self.on_confirm)
        self.cancel_button.clicked.connect(self.reject)

    def on_confirm(self):
        try:
            # 获取输入的参数值
            param1 = self.param1_input.text()
            param2 = self.param2_input.text()
            param3 = self.param3_input.text()
            param4 = self.param4_input.text()
            param5 = self.param5_input.text()
            param6 = self.param6_input.text()
            param7 = self.param7_input.text()


            # 在这里处理设置逻辑，比如保存到模型
            print(f"参数1: {param1}, 参数2: {param2}, 参数3: {param3}, 参数4: {param4},参数5: {param5}, 参数6: {param6},参数7: {param7}")

            self.accept()  # 关闭对话框
        except Exception as e:
            print(f"出现异常: {e}")
            # 在这里处理异常，比如显示错误消息
            self.reject()


# 模型界面按钮点击事件类
class ModelStepManager:
    def __init__(self, main_window):
        self.main_window = main_window
        self.parameter_data = {}  # 初始化一个属性来存储 JSON 数据

        self.current_step = 0

        # 获取标签和按钮
        self.labelModelManage = self.main_window.findChild(QLabel, "labelModelManage")
        self.labelDataSetting = self.main_window.findChild(QLabel, "labelDataSetting")
        self.labelParameterSetting = self.main_window.findChild(QLabel, "labelParameterSetting")
        self.labelExperimentResult = self.main_window.findChild(QLabel, "labelExperimentResult")

        self.pBtnResetting = self.main_window.findChild(QPushButton, "pBtnResetting")
        self.pBtnModelBack = self.main_window.findChild(QPushButton, "pBtnModelBack")
        self.pBtnModelNext = self.main_window.findChild(QPushButton, "pBtnModelNext")
        self.pBtnAnalysis = self.main_window.findChild(QPushButton, "pBtnAnalysis")

        # 获取页面
        self.stacked_widget = self.main_window.findChild(QStackedWidget, "widgetBtnColumn")

        self.page_model_manage = self.stacked_widget.findChild(QWidget, "widgetModelManage")
        self.page_data_setting = self.stacked_widget.findChild(QWidget, "widgetDataSettings")
        self.page_parameter_setting = self.stacked_widget.findChild(QWidget, "widgetParameterSettings")
        self.page_experiment_result = self.stacked_widget.findChild(QWidget, "widgetExperimentalResult")
        self.page1 = self.stacked_widget.findChild(QWidget, "page")
        self.page2 = self.stacked_widget.findChild(QWidget, "page_2")
        self.page3 = self.stacked_widget.findChild(QWidget, "page_3")

        # self.tableWidgetConclusion = self.page_experiment_result.findChild(QTableWidget, "tableWidgetConclusion")
        # 连接按钮的点击事件
        self.pBtnResetting.clicked.connect(self.reset)
        self.pBtnModelBack.clicked.connect(self.prev_step)
        self.pBtnModelNext.clicked.connect(self.next_step)
        self.pBtnAnalysis.clicked.connect(self.analyze)

        # 初始更新步骤标签和按钮
        self.update_step_labels()
        self.update_buttons()

    def update_step_labels(self):
        # 训练/微调路径的标签
        labels_train_adjust = [
            self.labelModelManage,  # 对应 step 0
            self.labelDataSetting,  # 对应 step 1
            self.labelParameterSetting,  # 对应 step 2
            self.labelExperimentResult  # 对应 step 3
        ]

        # 推理路径的标签
        labels_reasoning = [
            self.labelModelManage,  # 对应 step 0
            self.labelDataSetting,  # 对应 step 4
            self.labelParameterSetting,  # 对应 step 5
            self.labelExperimentResult  # 对应 step 6
        ]

        # 定义颜色：当前步骤为蓝色，已完成的步骤为绿色，未完成的为白色
        active_color = QColor("#00aaff")
        completed_color = QColor("#aaff00")
        future_color = QColor("#ffffff")

        # 更新训练/微调路径标签的颜色
        if 0 <= self.current_step <= 3:
            for i, label in enumerate(labels_train_adjust):
                if i == self.current_step:
                    color = active_color  # 当前步骤
                elif i < self.current_step:
                    color = completed_color  # 已完成的步骤
                else:
                    color = future_color  # 未完成的步骤
                label.setStyleSheet(f"background-color: {color.name()}")

        # 更新推理路径标签的颜色
        elif 4 <= self.current_step <= 6:
            for i, label in enumerate(labels_reasoning):
                if (i + 3) == self.current_step:  # 对应 step 4, 5, 6
                    color = active_color
                elif (i + 3) < self.current_step:
                    color = completed_color
                else:
                    color = future_color
                label.setStyleSheet(f"background-color: {color.name()}")

        # 更新页面显示
        if self.current_step == 0:
            self.stacked_widget.setCurrentWidget(self.page_model_manage)
        elif self.current_step == 1:
            self.stacked_widget.setCurrentWidget(self.page_data_setting)
        elif self.current_step == 2:
            self.stacked_widget.setCurrentWidget(self.page_parameter_setting)
        elif self.current_step == 3:
            self.stacked_widget.setCurrentWidget(self.page_experiment_result)
        elif self.current_step == 4:
            self.stacked_widget.setCurrentWidget(self.page1)
        elif self.current_step == 5:
            self.stacked_widget.setCurrentWidget(self.page2)
        elif self.current_step == 6:
            self.stacked_widget.setCurrentWidget(self.page3)

    def update_buttons(self):
        # 更新按钮状态
        self.pBtnResetting.setEnabled(self.current_step > 0)
        self.pBtnModelBack.setEnabled(self.current_step > 0)
        self.pBtnModelNext.setEnabled(self.current_step < 6 and self.current_step != 3)
        self.pBtnAnalysis.setEnabled(self.current_step == 3 or self.current_step == 6)

    def reset(self):
        self.current_step = 0
        self.update_step_labels()
        self.update_buttons()

    def prev_step(self):
        if self.current_step > 0 and self.current_step != 4:
            self.current_step -= 1
            self.update_step_labels()
            self.update_buttons()
        else:
            self.reset()
    def next_step(self):
        # 判断当前步骤是否为 0
        if self.current_step == 0:
            # 检查 tableWidget_model 中是否有选择的 radio button
            selected_row = None
            for row in range(self.main_window.ui.tableWidget_model.rowCount()):
                # 获取单元格中的 QWidget
                cell_widget = self.main_window.ui.tableWidget_model.cellWidget(row, 0)

                if cell_widget:
                    # 从 QWidget 中查找 QRadioButton
                    radio_button = cell_widget.findChild(QRadioButton)
                    if radio_button and radio_button.isChecked():
                        selected_row = row
                        # 选中 rBtnReasoning 时，跳转到 step 4
                        if self.main_window.ui.rBtnReasoning.isChecked():
                            self.current_step = 4
                            self.update_step_labels()
                            self.update_buttons()
                            return  # 直接返回，防止继续执行
                        break

            # 如果没有选中任何 radio button，弹出提示框
            if selected_row is None:
                QMessageBox.warning(self.main_window, "警告", "请先选择一个模型")
                return

        # 检查当前步骤是否为 rBtnTrain 或 rBtnAdjust 正常流程，处理步骤 1 到 3 的跳转
        if self.main_window.ui.rBtnTrain.isChecked() or self.main_window.ui.rBtnAdjust.isChecked():
            if self.current_step == 2:
                # 如果下一步是进入第 3 步，提前收集参数数据
                self.current_step += 1
                self.parameter_data = {
                    "parameter_setting": {
                        "task_name": self.main_window.ui.lEditTaskName.text(),
                        "task_type": self.main_window.ui.cmbBoxTaskType.currentText(),
                        "model_type": self.main_window.ui.cmbBoxModelType.currentText(),
                        "submodel": self.get_selected_submodel_data(),  # 获取选中子模型
                        "train": self.main_window.ui.spBoxTrain.value(),
                        "verification": self.main_window.ui.spBoxVerification.value(),
                        "test": self.main_window.ui.spBoxTest.value(),
                        "fill_null": self.main_window.ui.checkBox.isChecked(),
                        "iterations": self.main_window.ui.cmbBoxIteration.currentText(),
                        "assessment": self.get_selected_assessment_data()  # 获取选中评估数据
                    }
                }
                self.main_window.hyperparameter_data.update(self.parameter_data)
                # 打印 JSON 数据
                print(json.dumps(self.main_window.hyperparameter_data, ensure_ascii=False, indent=4))
                self.update_step_labels()
                self.update_buttons()

            elif self.current_step < 3:
                self.current_step += 1
                self.update_step_labels()
                self.update_buttons()

        # 检查是否选中了 rBtnReasoning，处理步骤 4 到 6 的跳转
        if self.main_window.ui.rBtnReasoning.isChecked():
            if 4 <= self.current_step < 6:
                self.current_step += 1
                self.update_step_labels()
                self.update_buttons()

    def get_selected_submodel_data(self):
        # 获取 tableWidgetSubModel 中选中行的第二列数据
        selected_submodels = []  # 用于存储选中的子模型名称

        for row in range(self.main_window.ui.tableWidgetSubModel.rowCount()):
            cell_widget = self.main_window.ui.tableWidgetSubModel.cellWidget(row, 0)
            if cell_widget:
                check_box = cell_widget.findChild(QCheckBox)  # 查找复选框
                if check_box and check_box.isChecked():
                    # 获取第二列的数据
                    submodel_item = self.main_window.ui.tableWidgetSubModel.item(row, 1)
                    if submodel_item:
                        selected_submodels.append(submodel_item.text())  # 添加到列表中

        return selected_submodels  # 返回选中的子模型列表


    def get_selected_assessment_data(self):
        # 获取 tableWidgetSubModel 中选中行的第二列数据
        selected_assessment = []  # 用于存储选中的子模型名称

        for row in range(self.main_window.ui.tableWidgetAssess.rowCount()):
            cell_widget = self.main_window.ui.tableWidgetAssess.cellWidget(row, 0)
            if cell_widget:
                check_box = cell_widget.findChild(QCheckBox)
                if check_box and check_box.isChecked():
                    # 获取第二列的数据
                    assessment_item = self.main_window.ui.tableWidgetAssess.item(row, 1)
                    selected_assessment.append(assessment_item.text())  # 添加到列表中
        return selected_assessment

    def analyze(self):
        # 从 parameter_setting 中获取参数
        parameters = self.main_window.hyperparameter_data.get("parameter_setting", {})
        if isinstance(parameters, dict):
            try:
                # 提取 task_type 和 model_type 参数
                task_type = str(parameters.get("task_type")) if parameters.get("task_type") else None
                model_type = str(parameters.get("model_type")) if parameters.get("model_type") else None
            except Exception as e:
                print(f"Error extracting parameters: {e}")

        # 获取三个模型的超参数
        hyperparams0 = self.main_window.hyperparameter_data.get("Hyperparameter0", {})
        # 确保 hyperparams 是一个字典
        if isinstance(hyperparams0, dict):
            try:
                # 提取七个参数，并确保 test_size 被正确转换为浮点数
                gb_param1 = float(hyperparams0.get("param1")) if hyperparams0.get("param1") else None  # test_size
                gb_param2 = int(hyperparams0.get("param2")) if hyperparams0.get("param2") else None
                gb_param3 = float(hyperparams0.get("param3")) if hyperparams0.get("param3") else None
                gb_param4 = int(hyperparams0.get("param4")) if hyperparams0.get("param4") else None
                gb_param5 = int(hyperparams0.get("param5")) if hyperparams0.get("param5") else None
                gb_param6 = int(hyperparams0.get("param6")) if hyperparams0.get("param6") else None
                gb_param7 = int(hyperparams0.get("param7")) if hyperparams0.get("param7") else None
                # 将参数传回 hyperparams0
                hyperparams0["param1"] = gb_param1
                hyperparams0["param2"] = gb_param2
                hyperparams0["param3"] = gb_param3
                hyperparams0["param4"] = gb_param4
                hyperparams0["param5"] = gb_param5
                hyperparams0["param6"] = gb_param6
                hyperparams0["param7"] = gb_param7
            except Exception as e:
                print(f"Error extracting parameters: {e}")
        else:
            # 如果 hyperparams 不是字典，给所有参数设置为 None
            hyperparams0 = {
                "param1": None,"param2": None,"param3": None,"param4": None,"param5": None,"param6": None,"param7": None
            }
        print(hyperparams0, "=====================")

        hyperparams1 = self.main_window.hyperparameter_data.get("Hyperparameter1", {})
        if isinstance(hyperparams1, dict):
            try:
                # 提取七个参数，并确保 test_size 被正确转换为浮点数
                svm_param1 = float(hyperparams1.get("param1")) if hyperparams1.get("param1") else None  # test_size
                svm_param2 = int(hyperparams1.get("param2")) if hyperparams1.get("param2") else None
                svm_param3 = float(hyperparams1.get("param3")) if hyperparams1.get("param3") else None
                svm_param4 = int(hyperparams1.get("param4")) if hyperparams1.get("param4") else None
                svm_param5 = int(hyperparams1.get("param5")) if hyperparams1.get("param5") else None
                svm_param6 = int(hyperparams1.get("param6")) if hyperparams1.get("param6") else None
                svm_param7 = int(hyperparams1.get("param7")) if hyperparams1.get("param7") else None
                # 将参数传回 hyperparams1
                hyperparams1["param1"] = svm_param1
                hyperparams1["param2"] = svm_param2
                hyperparams1["param3"] = svm_param3
                hyperparams1["param4"] = svm_param4
                hyperparams1["param5"] = svm_param5
                hyperparams1["param6"] = svm_param6
                hyperparams1["param7"] = svm_param7
            except Exception as e:
                print(f"Error extracting parameters: {e}")
        else:
            # 如果 hyperparams 不是字典，给所有参数设置为 None
            hyperparams1 = {
                "param1": None,"param2": None,"param3": None,"param4": None,"param5": None,"param6": None,"param7": None
            }
        print(hyperparams1, "=====================")

        hyperparams2 = self.main_window.hyperparameter_data.get("Hyperparameter2", {})
        print(hyperparams2, "=====================")

        if self.current_step == 3:
            self.update_step_labels()
            self.update_buttons()
            self.labelExperimentResult.setStyleSheet(f"background-color: #aaff00")

            params_gb = {
                k: v for k, v in {
                    'task_type': task_type,
                    'model_type': model_type,
                    'test_size': hyperparams0.get("param1"),
                    'random_state': hyperparams0.get("param2"),
                    'learning_rate': hyperparams0.get("param3"),
                    'max_depth': hyperparams0.get("param4"),
                    'min_samples_leaf': hyperparams0.get("param5"),
                    'min_samples_split': hyperparams0.get("param6"),
                    'n_estimators': hyperparams0.get("param7"),
                }.items() if v is not None
            }

            params_svr = {
                k: v for k, v in {
                    'task_type': task_type,
                    'model_type': model_type,
                    'test_size': hyperparams0.get("param1"),
                    'random_state': hyperparams0.get("param2"),
                    'kernel': hyperparams0.get("param3"),
                    'C': hyperparams0.get("param4"),
                    'epsilon':  hyperparams0.get("param5"),
                    'gamma': hyperparams0.get("param6"),
                    'max_iter':hyperparams0.get("param7"),
                }.items() if v is not None
            }

            params_rid = {
                k: v for k, v in {
                    'task_type': task_type,
                    'model_type': model_type,
                    'test_size': hyperparams0.get("param1"),
                    'random_state': hyperparams0.get("param2"),
                    'alpha': hyperparams0.get("param3"),
                }.items() if v is not None
            }
            def train_model(model_class, task_type, model_type, excel_path, features, target, **kwargs):
                # 使用 setdefault 设置默认值
                model_instance = model_class(task_type, model_type, excel_path, features, target, **kwargs)
                results = model_instance.train()

                model_instance.plot_loss_curve()
                return results

            excel_path = r'C:\Users\13945\Desktop\MLDS铝合金成分设计数据.xlsx'
            features = ['Si/％', 'Mn/％', 'Zn/％', 'Mg/％', 'Cu/％', 'Cr/％', 'Zr/％', 'Ti/％', 'Fe/％', 'Ni/％', 'other']
            target = ['Ultimate tensile strength/MPa']
            tasks = [
                delayed(train_model)(GradientBoostingModel, **params_gb, excel_path=excel_path, features=features,
                                     target=target),
                delayed(train_model)(SupportVectorMachineModel, **params_svr, excel_path=excel_path, features=features,
                                     target=target),
                delayed(train_model)(RidgeRegressionModel, **params_rid, excel_path=excel_path, features=features,
                                     target=target)
            ]

            results = Parallel(n_jobs=-1)(tasks)

            # 打印结果
            for result in results:
                # 获取模型训练的结果
                model_result = result
                if model_result is not None:
                    print(json.dumps(model_result, ensure_ascii=False, indent=4))
                    # 将训练结果保存到主窗口对象
                    self.main_window.model_results = model_result
                    print("model_results is", self.main_window.model_results)
                    # 更新表格显示结果
                    table_manager = ModelTableResultManager(self.main_window)
                    table_manager.update_table(model_result)
                    print("------------------------", self.parameter_data.get('parameter_setting', {}).get('submodel', []))

            # 触发更新以显示第一张图片（可选）
            # 添加图片和文本到下拉框
            self.controller = ImageComboBoxController(self.main_window)
            self.controller.add_item('梯度提升树', r'C:\Users\13945\Desktop\picture\plot1.png')
            self.controller.add_item('支持向量机', r'C:\Users\13945\Desktop\picture\plot2.png')
            self.controller.add_item('岭回归', r'C:\Users\13945\Desktop\picture\plot3.png')

            self.controller.connect_signals()
            self.controller.initialize_combobox()  # 初始化下拉框并更新图像
            # controller.connect_signals()



        if self.current_step == 6:
            self.update_step_labels()
            self.update_buttons()
            self.labelExperimentResult.setStyleSheet(f"background-color: #aaff00")


# 数据界面绘制直方图类
class HistogramWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)
        layout = QVBoxLayout(self)
        layout.addWidget(self.canvas)
        self.setLayout(layout)

    def plot_histogram(self, data):
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        self.figure.clear()
        ax = self.figure.add_subplot(111)

        # 绘制直方图
        try:
            # 绘制直方图
            if pd.api.types.is_numeric_dtype(data):
                ax.hist(data, bins=20, edgecolor='black')
                ax.set_title(f'{data.name} 直方图')
                ax.set_xlabel(f'{data.name}')
                ax.set_ylabel('Frequency')
            else:
                data.value_counts().plot(kind='bar', ax=ax)
                ax.set_title(f'{data.name} 频数图')
                ax.set_xlabel(f'{data.name}')
                ax.set_ylabel(f'Count({data.name})')

            self.canvas.draw()

        except Exception as e:
            # 弹出错误对话框
            QMessageBox.critical(self, "绘图错误", "绘图失败，请更改数据类型重试。错误信息: " + str(e))

    def clear_plot(self):
        self.figure.clear()
        self.canvas.draw()

# 数据界面界面三
class CustomPage3(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.histogram = HistogramWidget(parent=self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.histogram)
        self.setLayout(layout)

    def plot_histogram(self, data):
        self.histogram.plot_histogram(data)

    def clear_plot(self):
        self.histogram.clear_plot()

# 数据界面界面二
class CustomPage2(QWidget):
    visualize_signal = pyqtSignal(str)  # 定义信号

    def __init__(self, parent=None):
        super().__init__(parent)

        # 创建主布局
        self.main_layout = QVBoxLayout(self)

        # 添加标题行
        self.add_header()

        # 创建一个ScrollArea以处理大量数据
        self.scroll_area = QScrollArea(self)
        self.scroll_area.setWidgetResizable(True)
        self.scroll_content = QWidget()
        self.scroll_layout = QVBoxLayout(self.scroll_content)
        self.scroll_area.setWidget(self.scroll_content)


        # 将ScrollArea添加到主布局中
        self.main_layout.addWidget(self.scroll_area)
        self.setLayout(self.main_layout)  # 确保设置了布局

    def add_header(self):
        header_layout = QHBoxLayout()
        header_labels = ['属性名', '数据类型', '缺失数目', '数据', '操作']

        for text in header_labels:
            label = QLabel(text)
            label.setStyleSheet("border: 1px solid red;")  # 设置边框以调试
            label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)  # 设置为伸缩策略
            header_layout.addWidget(label)

        self.main_layout.addLayout(header_layout)

    def add_row(self, attr_name, data_type, missing_count, data_summary):
        row_widget = QWidget()
        row_layout = QHBoxLayout(row_widget)

        # 创建并添加每一列
        row_layout.addWidget(QLabel(attr_name))
        row_layout.addWidget(QLabel(data_type))
        row_layout.addWidget(QLabel(str(missing_count)))
        row_layout.addWidget(QLabel(data_summary))

        # 操作按钮
        visualize_button = QPushButton('可视化')
        # 为按钮连接槽函数
        visualize_button.clicked.connect(lambda: self.visualize_signal.emit(attr_name))
        row_layout.addWidget(visualize_button)

        # 将行添加到滚动区域的布局中
        self.scroll_layout.addWidget(row_widget)

    def clear_rows(self):
        # 清除滚动区域的所有行
        while self.scroll_layout.count():
            child = self.scroll_layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()



class MenuItem(QWidget):
    def __init__(self, text, icon):
        super(MenuItem, self).__init__()
        lay = QHBoxLayout()
        labelIcon = QLabel()
        labelIcon.setPixmap(QtGui.QPixmap(icon))
        labelIcon.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
        labelIcon.setContentsMargins(5, 0, 5, 0)
        lay.addWidget(labelIcon)
        labelItemName = QLabel(text)
        labelItemName.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
        labelItemName.setStyleSheet('''
            font-family: "Microsoft YaHei";
            font-weight: 400;
            font-size: 14px;
            color: #dcefff;
            border: 1px solid rgba(0, 0, 0, 0);
        ''')
        lay.addWidget(labelItemName)
        labelIndicator = QLabel()
        labelIndicator.setPixmap(QtGui.QPixmap(":/右箭头.png"))
        labelIndicator.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
        lay.addWidget(labelIndicator)
        lay.setSpacing(0)
        self.setLayout(lay)
        self.icon = labelIcon

    def setIcon(self, icon):
        self.icon.setPixmap(QtGui.QPixmap(icon))


class MenuManagerParameterSettings:
    def __init__(self, list_widget_menu, scroll_area, widgets):
        self.list_widget_menu = list_widget_menu
        self.scroll_area = scroll_area
        self.widgets = widgets  # 传入右侧的各个 QWidget 对象，分别对应每个设置项
        self.menu_items = []

        # 初始化菜单项
        self.init_menu_items()

        # 连接菜单项选择改变的信号
        self.list_widget_menu.currentRowChanged.connect(self.scroll_to_setting)

    def init_menu_items(self):
        # 添加菜单项到 listWidgetMenu 中
        self.menu_items.append(self.add_menu_item('模型设置', ":/模型设置.png"))
        self.menu_items.append(self.add_menu_item('参数设置', ":/参数设置.png"))
        self.menu_items.append(self.add_menu_item('模型训练', ":/模型训练.png"))

        # 设置初始状态为第一个菜单项
        self.list_widget_menu.setCurrentRow(0)

    def add_menu_item(self, text, icon):
        item = QListWidgetItem()
        self.list_widget_menu.addItem(item)
        item.setSizeHint(QtCore.QSize(100, 60))
        menu_item = MenuItem(text, icon)
        self.list_widget_menu.setItemWidget(item, menu_item)
        return menu_item

    def reset_menu_icons(self):
        # 重置所有菜单项的图标
        self.menu_items[0].setIcon(":/模型设置.png")
        self.menu_items[1].setIcon(":/参数设置.png")
        self.menu_items[2].setIcon(":/模型训练.png")

    def scroll_to_setting(self, row):
        # 根据选中的行，滚动到相应的设置项
        if row == 0:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['model_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[0].setIcon(":/基本设置-选中.png")
        elif row == 1:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['data_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[1].setIcon(":/路径设置-选中.png")
        elif row == 2:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['train_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[2].setIcon(":/升级设置-选中.png")
class MenuManagerExperimentalResult:
    def __init__(self, list_widget_menu, scroll_area, widgets):
        self.list_widget_menu = list_widget_menu
        self.scroll_area = scroll_area
        self.widgets = widgets  # 传入右侧的各个 QWidget 对象，分别对应每个设置项
        self.menu_items = []

        # 初始化菜单项
        self.init_menu_items()

        # 连接菜单项选择改变的信号
        self.list_widget_menu.currentRowChanged.connect(self.scroll_to_setting)

    def init_menu_items(self):
        # 添加菜单项到 listWidgetMenu 中
        self.menu_items.append(self.add_menu_item('训练进度', ":/训练进度.png"))
        self.menu_items.append(self.add_menu_item('测试集结论', ":/测试集结论.png"))
        self.menu_items.append(self.add_menu_item('损失曲线', ":/损失曲线.png"))

        # 设置初始状态为第一个菜单项
        self.list_widget_menu.setCurrentRow(0)

    def add_menu_item(self, text, icon):
        item = QListWidgetItem()
        self.list_widget_menu.addItem(item)
        item.setSizeHint(QtCore.QSize(100, 60))
        menu_item = MenuItem(text, icon)
        self.list_widget_menu.setItemWidget(item, menu_item)
        return menu_item

    def reset_menu_icons(self):
        # 重置所有菜单项的图标
        self.menu_items[0].setIcon(":/训练进度.png")
        self.menu_items[1].setIcon(":/测试集结论.png")
        self.menu_items[2].setIcon(":/损失曲线.png")

    def scroll_to_setting(self, row):
        # 根据选中的行，滚动到相应的设置项
        if row == 0:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['Train_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[0].setIcon(":/训练进度-选中.png")
        elif row == 1:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['Conclusion_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[1].setIcon(":/测试集结论-选中.png")
        elif row == 2:
            self.scroll_area.verticalScrollBar().setSliderPosition(self.widgets['Loss_setting'].pos().y())
            self.reset_menu_icons()
            self.menu_items[2].setIcon(":/损失曲线-选中.png")

class DataManagerApp(QWidget):
    def __init__(self):
        super().__init__()
        # 存储超参数 JSON 数据
        self.hyperparameter_data = {"Hyperparameter0": "", "Hyperparameter1": "", "Hyperparameter2": ""}


        self.ui = Ui_DataManagerwidget()
        self.ui.setupUi(self)

        # 创建菜单
        self.createMenus()

        # 绑定按钮点击事件到相应的槽函数
        self.ui.toolButtonP1.clicked.connect(lambda: self.select_page(self.ui.page1))
        self.ui.toolButtonP2.clicked.connect(lambda: self.select_page(self.ui.page2))
        self.ui.toolButtonP3.clicked.connect(lambda: self.select_page(self.ui.page3))

        # 隐藏窗体顶部
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        # 设置鼠标追踪
        self.setMouseTracking(True)
        # 设置拖动相关变量
        self.is_maximized = False
        self.initDrag()

        # 记录初始位置和大小
        self.initial_geometry = self.geometry()

        # 连接窗口控制按钮
        self.ui.pBtnClose.clicked.connect(self.close)
        self.ui.pBtnBig.clicked.connect(self.toggle_maximize)
        self.ui.pBtnSmall.clicked.connect(self.showMinimized)

        # 加载模型页面第一页模型管理表格==================================================================
        # 实例化 ModelTableManager
        self.model_table_manager = ModelTableProjectManager(self.ui.tableWidget_model)
        self.model_table_manager.setup_modelTable()
        self.projects = load_projects()
        self.filtered_projects = self.projects  # 保持当前的过滤结果
        self.model_table_manager.load_model_table(self.filtered_projects)
        # 记录被选中的行
        self.selected_row = None
        # QStackedWidget按钮控制页面跳转
        self.step_manager = ModelStepManager(self)


        # 加载模型页面第三页模型管理表格==================================================================
        self.submodel_table_manager = SubModelTableManager(self.ui.tableWidgetSubModel, self)
        self.submodel_table_manager.setup_modelTable([100, 500, 300])
        # 加载数据并显示在表格中
        subModel = [
            {"name": "梯度提升树"},
            {"name": "支持向量机"},
            {"name": "岭回归"},
        ]  # 存储从JSON中获取的数据
        self.submodel_table_manager.load_model_table(subModel)
        # 加载模型页面第三页参数设置表格==================================================================
        self.assess_table_manager = SubModelTableManager(self.ui.tableWidgetAssess, self)
        self.assess_table_manager.setup_modelTable([100, 700])
        # 加载数据并显示在表格中
        assess = [
            {"name": "MSE"},
            {"name": "R²"},
        ]  # 存储从JSON中获取的数据
        self.assess_table_manager.load_model_table(assess)
        # ====================================================================================
        # 左侧菜单项与右侧设置项的对应关系
        WidgetsParameterSetting = {
            'model_setting': self.ui.widgetModelSettingTitle,
            'data_setting': self.ui.widgetDataSettingTitle,
            'train_setting': self.ui.widgetTrainParametersTitle,
        }
        # 创建参数设置页菜单管理器
        self.menu_manager_setting = MenuManagerParameterSettings(self.ui.listWidgetMenu, self.ui.scrollArea, WidgetsParameterSetting)
        # 左侧菜单项与右侧设置项的对应关系
        WidgetsExperimentalResult = {
            'Train_setting': self.ui.widgetTrainProgressTitle,
            'Conclusion_setting': self.ui.widgetConclusionTitle,
            'Loss_setting': self.ui.widgetLossTitle,
        }
        # 创建参数设置页菜单管理器
        self.menu_manager_result = MenuManagerExperimentalResult(self.ui.listWidgetMenu_2, self.ui.scrollArea_2, WidgetsExperimentalResult)
        # 获取控件做隐藏按钮操作==================================================================
        self.rBtnTrain = self.findChild(QRadioButton, "rBtnTrain")
        self.rBtnAdjust = self.findChild(QRadioButton, "rBtnAdjust")
        self.rBtnReasoning = self.findChild(QRadioButton, "rBtnReasoning")

        self.pBtnTrain = self.findChild(QPushButton, "pBtnTrain")
        self.pBtnAdjust = self.findChild(QPushButton, "pBtnAdjust")
        self.pBtnReasoning = self.findChild(QPushButton, "pBtnReasoning")
        self.pBtnLog = self.findChild(QPushButton, "pBtnLog")
        self.pBtnDelete = self.findChild(QPushButton, "pBtnDelete")

        self.widgetModelAnalysisBtn = self.findChild(QWidget, "widgetModelAnalysisBtn")

        # 连接信号和槽
        self.rBtnTrain.toggled.connect(self.update_buttons)
        self.rBtnAdjust.toggled.connect(self.update_buttons)
        self.rBtnReasoning.toggled.connect(self.update_buttons)
        # 连接信号和槽
        self.pBtnTrain.clicked.connect(self.show_train_dialog)



        self.update_buttons()  # 初始化时更新按钮显示状态
        # QStackedWidget按钮控制页面跳转==================================================================
        self.stacked_widget = self.findChild(QStackedWidget, "stackedWidget_2")
        self.pBtnData = self.findChild(QPushButton, "pBtnData")
        self.pBtnModel = self.findChild(QPushButton, "pBtnModel")
        # 默认显示第一个数据页面
        self.stacked_widget.setCurrentIndex(0)
        # 连接按钮的点击事件
        self.pBtnData.clicked.connect(self.show_data_page)
        self.pBtnModel.clicked.connect(self.show_model_page)

        # 初始化页面和按钮状态
        self.setup_buttons()

        # 默认选中第一个按钮
        self.select_button(self.ui.toolButtonP1)

        # 创建并添加自定义页面 CustomPage2 到 page2 中
        self.custom_page2 = CustomPage2()
        self.ui.page2.layout().addWidget(self.custom_page2)  # 使用现有的布局
        self.custom_page2.visualize_signal.connect(self.visualize_column)

        # # 创建 CustomPage3 实例
        self.custom_page3 = CustomPage3()
        # 清除现有的布局内容
        while self.ui.page3.layout().count():
            child = self.ui.page3.layout().takeAt(0)
            if child.widget():
                child.widget().deleteLater()

        # 添加 CustomPage3 到 page3
        self.ui.page3.layout().addWidget(self.custom_page3)
        # self.ui.stackedWidget.addWidget(self.custom_page3)   #新增一个页面
        # 初始化uploaded_data
        self.uploaded_data = None  # 用于存储上传的Excel数据
        # 连接 stackedWidget 页面切换信号
        self.ui.stackedWidget.currentChanged.connect(self.on_page_changed)
        # 初始化表头右键菜单功能
        self.init_table_widget_context_menu()

        self.header_labels = {}  # 用于存储表头标签的持久化字典

        self.dialog_open = False
    # 获取parameter_data==================================================================

    # def pr_parameter_data(self):
    #     parameter_data = self.step_manager.get_parameter_data()
    #     print(json.dumps(parameter_data, ensure_ascii=False, indent=4))
    def show_train_dialog(self):
        dialog = TrainModelDialog(self)
        if dialog.exec() == QDialog.DialogCode.Accepted:
            # 获取输入内容
            name = dialog.name_input.text()
            type_ = dialog.type_input.text()
            submodel = dialog.submodel_input.text()

            # 获取当前时间
            created_time = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            # 获取导入的Excel数据行数
            train_set = f"{self.uploaded_data.shape[0]}条" if self.uploaded_data is not None else ""

            # 创建新的模型数据条目
            new_entry = {
                "ID": "",
                "name": name,
                "type": type_,
                "created_time": created_time,
                "state": "已创建",
                "submodel": submodel,
                "train_set": train_set,
                "Validation_set": ""
            }

            # 将新条目加入项目列表
            self.projects.append(new_entry)
            # 保存到JSON文件
            save_projects(self.projects)
            # 刷新表格
            self.model_table_manager.load_model_table(self.filtered_projects)

            # 禁用 pBtnTrain 按钮
            self.pBtnTrain.setEnabled(False)
            self.update_buttons()  # 更新按钮状态
    # =================================================
    def show_data_page(self):
        self.stacked_widget.setCurrentIndex(0)
    def show_model_page(self):
        self.stacked_widget.setCurrentIndex(1)
    # =================================================
    def update_buttons(self):
        # 根据哪个 QRadioButton 被选中来更新按钮的显示状态
        if self.rBtnTrain.isChecked():
            self.show_buttons([self.pBtnTrain])

            self.filtered_projects = [project for project in self.projects if project.get("state") == "已创建"]
            self.model_table_manager.load_model_table(self.filtered_projects)  # 加载筛选后的数据

            # 禁用 tableWidget_model 中的所有 RadioButton
            self.set_radio_buttons_enabled(False)
            # 清除所有的选中状态
            self.clear_all_radio_buttons()

        elif self.rBtnAdjust.isChecked() or self.rBtnReasoning.isChecked():
            if self.rBtnAdjust.isChecked():
                self.show_buttons([self.pBtnAdjust, self.pBtnLog, self.pBtnDelete])
            else:
                self.show_buttons([self.pBtnReasoning, self.pBtnLog, self.pBtnDelete])
            self.filtered_projects = [project for project in self.projects if project.get("state") == "已完成"]
            self.model_table_manager.load_model_table(self.filtered_projects)  # 加载筛选后的数据

            # 启用 tableWidget_model 中的所有 RadioButton
            self.set_radio_buttons_enabled(True)
        else:
            self.show_buttons([])  # 如果没有任何 radio button 选中，隐藏所有按钮

    def clear_all_radio_buttons(self):
        for row in range(self.ui.tableWidget_model.rowCount()):
            radio_button = self.ui.tableWidget_model.cellWidget(row, 0)
            if radio_button and isinstance(radio_button, QtWidgets.QRadioButton):
                if radio_button.isChecked():
                    radio_button.setChecked(False)
        QApplication.processEvents()  # 强制处理挂起的事件

    def set_radio_buttons_enabled(self, enabled):
        # 启用或禁用 tableWidget_model 中的所有 RadioButton
        for row in range(self.ui.tableWidget_model.rowCount()):
            radio_button = self.ui.tableWidget_model.cellWidget(row, 0)
            if radio_button:
                radio_button.setEnabled(enabled)

    def show_buttons(self, buttons):
        # 隐藏所有按钮
        for btn in [self.pBtnTrain, self.pBtnAdjust, self.pBtnReasoning, self.pBtnLog, self.pBtnDelete]:
            btn.setVisible(False)
        # 仅显示指定的按钮
        for btn in buttons:
            btn.setVisible(True)
    # =================================================
    def init_table_widget_context_menu(self):
        # 获取 tableWidget（在 page1 中）
        table_widget = self.ui.page1.findChild(QTableWidget, "tableWidget")

        if table_widget:
            # 设置行和列的右键菜单
            table_widget.horizontalHeader().setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
            table_widget.verticalHeader().setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)

            # 绑定右键点击事件到槽函数
            table_widget.horizontalHeader().customContextMenuRequested.connect(self.show_horizontal_header_menu)
            table_widget.verticalHeader().customContextMenuRequested.connect(self.show_vertical_header_menu)

    def show_horizontal_header_menu(self, position):
        # 将位置转换为列索引
        column_index = self.ui.tableWidget.horizontalHeader().logicalIndexAt(position)

        # 获取对应列的表头文本
        header_item = self.ui.tableWidget.horizontalHeaderItem(column_index)
        header_text = header_item.text() if header_item else "Unknown"

        # 在水平表头位置显示右键菜单
        header_menu = QMenu(self)
        header_menu.addAction("水平表头操作1", lambda: self.horizontal_header_action1(position, header_text))
        header_menu.addAction("水平表头操作2", self.horizontal_header_action2)
        header_menu.addAction("水平表头操作3", self.horizontal_header_action3)
        header_menu.exec(self.ui.tableWidget.horizontalHeader().mapToGlobal(position))

    def show_vertical_header_menu(self, position):
        # 在垂直表头位置显示右键菜单
        header_menu = QMenu(self)
        header_menu.addAction("垂直表头操作1", self.vertical_header_action1)
        header_menu.addAction("垂直表头操作2", self.vertical_header_action2)
        header_menu.exec(self.ui.tableWidget.verticalHeader().mapToGlobal(position))

    def horizontal_header_action1(self, position, header_text):
        try:
            header = self.ui.tableWidget.horizontalHeader()
            column_index = header.logicalIndexAt(position)
            print("column_index is", column_index)
            if column_index != -1:
                self.show_type_setting_window(column_index, header_text)

                # selected_type_str = self.dialog.get_selected_type()
                # if selected_type_str:
                #     selected_type = type_mapping.get(selected_type_str, str)
                    # 现在可以使用 selected_type 作为 Python 类型进行操作
        except Exception as e:
            print(f"Error in horizontal_header_action1: {e}")
            QMessageBox.critical(self, "错误", f"发生错误: {e}")

    def show_type_setting_window(self, column_index, header_text):
        if self.dialog_open:
            return

        self.set_controls_enabled(False)  # 禁用主窗口控件
        self.dialog_open = True

        dialog = TypeSettingWindow(column_index, header_text, self.ui.tableWidget, self)
        dialog.setModal(True)  # 设置对话框为模态

        try:
            # 显示对话框并等待用户操作
            if dialog.exec() == QDialog.DialogCode.Accepted:
                # 获取用户选择的类型
                new_type = dialog.get_selected_type()
                # 获取当前列名（去掉标签）
                column_name = self.ui.tableWidget.horizontalHeaderItem(column_index).text().split('(')[0].strip()
                # 更新表头标签的持久化数据结构
                new_header_label = f"{column_name} ({new_type.capitalize()})"
                self.header_labels[column_name] = new_header_label
                try:
                    if new_type == "float":
                        self.uploaded_data[column_name] = self.uploaded_data[column_name].astype(float)
                    elif new_type == "object":
                        self.uploaded_data[column_name] = self.uploaded_data[column_name].astype(str)
                except Exception as e:
                    print(f"Error during type conversion: {e}")  # 捕获并打印异常
                    QMessageBox.critical(self, "错误", f"类型转换时发生错误: {e}")
        finally:
            # 确保对话框关闭后恢复主窗口控件的启用状态
            self.dialog_open = False
            self.set_controls_enabled(True)
    def set_controls_enabled(self, enabled: bool):
        # 根据需要禁用和启用主窗口中的控件
        self.ui.tableWidget.setEnabled(enabled)
        self.ui.widgetToolboxTop.setEnabled(enabled)
        self.ui.widgetDataModel.setEnabled(enabled)
        self.ui.widgetToolboxLeft.setEnabled(enabled)


    def horizontal_header_action2(self):
        print("水平表头操作2触发")

    def horizontal_header_action3(self):
        print("水平表头操作3触发")

    def vertical_header_action1(self):
        print("垂直表头操作1触发")

    def vertical_header_action2(self):
        print("垂直表头操作2触发")
    def select_page(self, page):
        if page == self.ui.page1:
            self.show_page1()
        elif page == self.ui.page2:
            self.show_page2()
        elif page == self.ui.page3:
            self.show_page3()

    # 隐藏自带框
    def initDrag(self):
        # 设置鼠标跟踪判断扳机默认值
        self.moveDrag = False

    def mousePressEvent(self, event):
        if (
                event.button() == Qt.MouseButton.LeftButton) and not self.toolButtonsUnderMouse() and self.ui.widgetTop.underMouse():
            if self.is_maximized:
                self.toggle_maximize()
                self.moveDragPosition = event.globalPosition().toPoint() - self.geometry().topLeft()
            else:
                self.moveDragPosition = event.globalPosition().toPoint() - self.pos()
            self.moveDrag = True
            event.accept()

    def mouseMoveEvent(self, event):
        if self.moveDrag:
            self.move(event.globalPosition().toPoint() - self.moveDragPosition)
            event.accept()

    def mouseReleaseEvent(self, event):
        self.moveDrag = False

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton and self.ui.widgetTop.underMouse():
            self.toggle_maximize()

    def toolButtonsUnderMouse(self):
        return self.ui.pBtnClose.underMouse() or self.ui.pBtnBig.underMouse() or self.ui.pBtnSmall.underMouse()

    def toggle_maximize(self):
        if self.is_maximized:
            self.setGeometry(self.initial_geometry)
            self.is_maximized = False
        else:
            self.initial_geometry = self.geometry()
            self.showMaximized()
            self.is_maximized = True


    # 菜单栏相关逻辑
    def createMenus(self):
        # 创建文件菜单
        self.fileMenu = QtWidgets.QMenu(self)
        # 创建“导入数据”菜单项，并为其添加二级菜单
        self.importDataMenu = QtWidgets.QMenu("导入数据", self)
        self.appendDataAction = self.importDataMenu.addAction("末尾追加")
        self.overwriteDataAction = self.importDataMenu.addAction("覆盖旧数据")

        # 将导入数据的二级菜单添加到文件菜单
        self.fileMenu.addMenu(self.importDataMenu)

        self.goBackAction = self.fileMenu.addAction("返回项目管理页")
        self.exitAction = self.fileMenu.addAction("退出")

        # 连接文件菜单项到槽函数
        self.appendDataAction.triggered.connect(self.append_data)
        self.overwriteDataAction.triggered.connect(self.overwrite_data)
        self.goBackAction.triggered.connect(self.goback)
        self.exitAction.triggered.connect(self.exitApp)

        # 将文件菜单连接到文件按钮
        self.ui.pBtnFile.setMenu(self.fileMenu)


        # 创建文件菜单
        self.editMenu = QtWidgets.QMenu(self)
        self.backAction = self.editMenu.addAction("上一步")
        self.nextAction = self.editMenu.addAction("下一步")

        self.backAction.triggered.connect(self.back)
        self.nextAction.triggered.connect(self.next)

        self.ui.pBtnEdit.setMenu(self.editMenu)

        self.windowsMenu = QtWidgets.QMenu(self)
        self.windowsAction = self.windowsMenu.addAction("窗口")
        self.windowsAction.triggered.connect(self.windows)
        self.ui.pBtnWindow.setMenu(self.windowsMenu)

        self.helpMenu = QtWidgets.QMenu(self)
        self.aboutAction = self.helpMenu.addAction("使用帮助")
        self.aboutAction.triggered.connect(self.about)
        self.ui.pBtnHelp.setMenu(self.helpMenu)
        self.uploaded_data = None  # 用于存储上传的Excel数据



        # 其他初始化逻辑
        self.ui.listWidgetMenu.setFixedWidth(180)
        self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint)
        self.ui.frame.setFrameStyle(QFrame.Shape.Panel)
    # 需要定义处理子菜单项点击的槽函数
    def append_data(self):
        # 实现末尾追加数据的逻辑
        pass

    def goback(self):
        pass

    def back(self):
        pass

    def next(self):
        pass

    def exitApp(self):
        QtWidgets.QApplication.quit()

    def edit(self):
        QtWidgets.QMessageBox.information(self, "编辑", "编辑信息")

    def windows(self):
        QtWidgets.QMessageBox.information(self, "窗口", "窗口信息")

    def about(self):
        QtWidgets.QMessageBox.information(self, "关于", "关于信息")


    # 槽函数用于切换页面
    def setup_buttons(self):
        # 绑定按钮点击事件到相应的槽函数
        self.ui.toolButtonP1.clicked.connect(lambda: self.select_button(self.ui.toolButtonP1))
        self.ui.toolButtonP2.clicked.connect(lambda: self.select_button(self.ui.toolButtonP2))
        self.ui.toolButtonP3.clicked.connect(lambda: self.select_button(self.ui.toolButtonP3))

    def select_button(self, button):
        # 取消所有按钮的选中状态
        self.ui.toolButtonP1.setProperty('selected', False)
        self.ui.toolButtonP2.setProperty('selected', False)
        self.ui.toolButtonP3.setProperty('selected', False)

        # 选中当前按钮
        button.setProperty('selected', True)

        # 刷新所有按钮的样式表
        self.ui.toolButtonP1.style().unpolish(self.ui.toolButtonP1)
        self.ui.toolButtonP1.style().polish(self.ui.toolButtonP1)
        self.ui.toolButtonP2.style().unpolish(self.ui.toolButtonP2)
        self.ui.toolButtonP2.style().polish(self.ui.toolButtonP2)
        self.ui.toolButtonP3.style().unpolish(self.ui.toolButtonP3)
        self.ui.toolButtonP3.style().polish(self.ui.toolButtonP3)

    def restore_header_labels(self):
        # 获取表头
        header = self.ui.tableWidget.horizontalHeader()
        model = self.ui.tableWidget.model()  # 获取模型对象

        for column_name, label in self.header_labels.items():
            # 遍历所有列来找到匹配的列名
            for column_index in range(header.count()):
                header_item = model.headerData(column_index, Qt.Orientation.Horizontal)
                if header_item and column_name in header_item:
                    # 更新表头数据
                    model.setHeaderData(column_index, Qt.Orientation.Horizontal, label)
                    print(f"Updated column '{column_name}' to '{label}'")
                    break

    def show_page1(self):
        try:

            self.ui.stackedWidget.setCurrentWidget(self.ui.page1)
            if self.uploaded_data is not None:
                self.populate_table()
                self.restore_header_labels()
        except Exception as e:
            print(f"Error in show_page1: {e}")
            QMessageBox.critical(self, "错误", f"切换到 Page 1 时发生错误: {e}")


    def show_page2(self):
        if self.ui.stackedWidget.currentWidget() != self.ui.page2:
            self.ui.stackedWidget.setCurrentWidget(self.ui.page2)
            print("Switched to page2")
            self.populate_custom_page2()  # 确保在切换页面时填充数据


    def overwrite_data(self):
        filePath, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xls *.xlsx);;All Files (*)")

        if filePath:
            try:
                df = pd.read_excel(filePath)
                self.uploaded_data = df
                print(f"Data loaded: {self.uploaded_data.shape[0]} rows, {self.uploaded_data.shape[1]} columns")
                self.populate_table()  # 填充表格
                self.populate_custom_page2()  # 填充CustomPage2
                self.ui.stackedWidget.setCurrentWidget(self.ui.page1)  # 切换到 page1 页面
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法加载Excel文件：{str(e)}")
        else:
            QMessageBox.information(self, "取消", "操作已取消")

    def populate_custom_page2(self):
        if self.uploaded_data is not None:
            self.custom_page2.clear_rows()  # 先清除现有行

            # 获取第一列的列名
            first_column_name = self.uploaded_data.columns[0]

            for col in self.uploaded_data.columns:
                # 跳过第一列的统计
                if col == first_column_name:
                    continue
                missing_count = self.uploaded_data[col].isnull().sum()

                if pd.api.types.is_numeric_dtype(self.uploaded_data[col]):
                    # 统计数字数据类型的均值、最小值和最大值
                    mean_value = self.uploaded_data[col].mean()
                    min_value = self.uploaded_data[col].min()
                    max_value = self.uploaded_data[col].max()
                    data_summary = f"均值({mean_value:.2f}), 最小值({min_value:.2f}), 最大值({max_value:.2f})"
                else:
                    # 统计非数字数据类型的唯一值及其计数
                    unique_values = self.uploaded_data[col].value_counts()
                    data_summary = ', '.join([f"{str(val)}({str(count)})" for val, count in unique_values.items()])
                # 使用最新的数据类型
                data_type = str(self.uploaded_data[col].dtype)

                self.custom_page2.add_row(
                    attr_name=col,
                    data_type=data_type,
                    missing_count=missing_count,
                    data_summary=data_summary
                )
        else:
            QMessageBox.warning(self, "No Data", "请先上传数据")

    def on_page_changed(self, index):
        print(f"Page changed to index: {index}")  # 打印页面索引
        print(f"Total pages: {self.ui.stackedWidget.count()}")  # 打印总页面数量
        page = self.ui.stackedWidget.widget(index)
        if page == self.ui.page1:
            self.select_button(self.ui.toolButtonP1)
        elif page == self.ui.page2:
            self.select_button(self.ui.toolButtonP2)
        elif page == self.ui.page3:
            self.select_button(self.ui.toolButtonP3)
    def check_page_data(self):
        if self.uploaded_data is not None:
            self.populate_table()

    # 在QTableWidget中展示数据
    def populate_table(self):
        if self.uploaded_data is not None:
            rows, cols = self.uploaded_data.shape
            self.ui.tableWidget.setRowCount(rows)
            self.ui.tableWidget.setColumnCount(cols)
            self.ui.tableWidget.setHorizontalHeaderLabels(self.uploaded_data.columns)

            for row in range(rows):
                for col in range(cols):
                    item = QTableWidgetItem(str(self.uploaded_data.iat[row, col]))
                    self.ui.tableWidget.setItem(row, col, item)

            self.ui.tableWidget.update()  # 强制刷新表格视图
        else:
            print("No data to populate")

    def show_page3(self):
        print("show_page3 called")
        # 检查数据是否已上传
        if self.uploaded_data is None or self.uploaded_data.empty:
            # 如果未上传数据或数据为空，弹出警告对话框并返回
            QMessageBox.warning(self, "警告", "请先上传有效数据！")
            return

        # 切换到 Page3 并绘制直方图
        self.ui.stackedWidget.setCurrentWidget(self.ui.page3)

        # 检查数据集是否包含至少一列
        if self.uploaded_data.shape[1] == 0:
            QMessageBox.warning(self, "警告", "数据集不包含任何列，无法绘制直方图！")
            return

        # 获取最后一列并绘制直方图
        last_column = self.uploaded_data.columns[-1]
        data = self.uploaded_data[last_column]

        # print(f"Data for histogram: {data.head()}")  # 打印数据检查内容
        # 清除当前图表
        self.custom_page3.clear_plot()
        # 绘制直方图
        self.custom_page3.plot_histogram(data)

    def visualize_column(self, attr_name):
        if self.uploaded_data is not None:
            column_data = self.uploaded_data[attr_name]
            print(f"可视化 {attr_name} 列的数据")
            # 切换到 page3
            # self.ui.stackedWidget.setCurrentWidget(self.custom_page3)
            # 切换到 page3
            self.select_page(self.ui.page3)
            # 使用 CustomPage3 的 plot_histogram 方法
            self.custom_page3.plot_histogram(column_data)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = DataManagerApp()
    window.show()
    sys.exit(app.exec())

